#!/usr/bin/python
# -*- coding: utf-8 -*- 

#       conq_svr.py
#       
#       Copyright 2008 Santiago Lezica <slezica0@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

#  Como no se me ocurría qué puto nombre ponerle (como prefijo) asumí que
# el nombre provisiorio de nuestro proyecto es "Conquista". Ya sé, súper
# original, pero sirve como codename. Ah, y lo de arriba me lo pone auto-
# máticamente el programa este jaja!

#  Este módulo incluye las clases necesarias para la comunicación por
# internet del programa.

import threading
import socket
import Queue
import sys
import datetime

# CLASES:
class ServerThread ( threading.Thread ):
	""" Clase simpe para un servidor, usando queues.  Es muy flexible porque
		sencillamente recibe clientes, les crea sus threads y acumula la data
		recibida en una clase Queue preseteada en tuplas con formato:
		(clientthread, data)"""

	def log(self, data, source = "SERVER"):
		dt = datetime.datetime.now()
		# Esto queda "SOURCE @ DD/MM/YY HH:MM:SS > DATA"
		data = "%s @ %s > %s \n" % (source, dt.strftime("%x %X"), data)
		sys.stdout.write(data)
		sys.stdout.flush()

		for i in self.logfiles:
			pass	# falta hacer esto de los logfiles.
			#i.write(data)
			#i.flush()


	def get_queue(self):
		# Devuelve la queue que se está usando. Très util.
		return self.Q

	def set_queue(self, newQ):
		#  Permite setear una nueva cola de instrucciones para pasar
		# a las instancias de la clase ClientThread. No lo veo usándose xD
		self.Q = Q


	def run(self):

		self.log("Bindeando/escuchando en %d (backlog=%d maxclients=%d)..." % (self.localport, self.backlog, self.maxclients))

		try:
			self.sock.bind(("", self.localport))
			self.sock.listen(self.backlog)

			self.running = True
			self.newclient_id = 0

		except socket.error, e:
			self.log("Socket error al intentar bindear/escuchar!")
			return

		self.log("Servidor iniciado correctamente.")

		while self.running:
			# A recibir conexiones:
			self.newclient_socket, self.newclient_addr = self.sock.accept()
			self.log("Conexión entrante desde %s" % (self.newclient_addr))
			
			if (len(self.clients) < self.maxclients):
				self.newclient_id += 1
				self.newclient_obj = ClientThread(self, self.newclient_id, self.newclient_socket, self.Q)

				self.clients.append((self.newclient_id, self.newclient_obj))
				self.log("Conexión aceptada. Cliente id=%d listo." % (self.newclient_id))

			else:
				self.newclient_socket.send("ACÁ NO ENTRÁS, GIL.")
				self.newclient_socket.close()

		self.log("Servidor interrumpido. Cerrando socket...")
		self.sock.close()
		self.log("Cerrado. Servidor terminado.")

	def __init__(self, localport = 4748, backlog = 3, maxclients = 10, logfiles = [], newQ = Queue.Queue()):
		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

		self.localport = localport
		self.backlog = backlog
		self.maxclients = maxclients

		self.Q = newQ # queue a pasar a las instancias de c/cliente
		self.clients = [] # lista de clientes

		self.logfiles = []
		self.logfiles.extend(logfiles) # para evitar el pasaje por referencia.

		self.running = False

		self.log("Clase servidor creada.")

		threading.Thread.__init__(self)


class ClientThread( threading.Thread ):

	def log(self, data):
		#Usamos el motor de log del servidor
		self.svr.log(data, "CLIENT (id=%d)" % (self.clientid))

	def run(self):
		self.log("Comenzando a enviar/recibir...")

		self.running = True

		while self.running:
			self.data = self.sock.recv(1024)
			self.log("recv %s" % (data))

		self.log("Cliente interrumpido, cerrando socket...")
		self.sock.close()
		self.log("Cerrado. Cliente terminado.")

	def __init__(self, theserver, clientid, thesocket, thequeue):
		self.clientid = clientid
		self.sock = thesocket
		self.Q = thequeue
		self.svr = theserver

		self.running = False
		
		self.log("Clase cliente creada.")

		threading.Thread.__init__(self)